import requests
import json
import pandas as pd
from datetime import datetime, timedelta
import logging
import time
from config import ALIYUN_APPCODE

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)

class StockApiClient:
    """股票市场API客户端"""
    
    def __init__(self, app_code=None):
        """初始化API客户端"""
        self.app_code = app_code or ALIYUN_APPCODE
        self.base_url = "https://stockapi.market.alicloudapi.com"
        self.headers = {
            "Authorization": f"APPCODE {self.app_code}"
        }
        self.logger = logging.getLogger('StockApiClient')
        self.logger.info(f"初始化API客户端，基础URL: {self.base_url}")
    
    def get_stock_quotes(self, symbols):
        """获取股票报价
        
        Args:
            symbols: 股票代码列表，如 ["sh000001", "sz000002"]
        
        Returns:
            包含股票报价信息的DataFrame
        """
        if not symbols:
            return pd.DataFrame()
        
        # 将列表转换为逗号分隔的字符串
        symbol_str = ",".join(symbols)
        
        # 构建请求URL
        url = f"{self.base_url}/hs/real"
        params = {
            "symbol": symbol_str
        }
        
        try:
            self.logger.info(f"请求股票报价API: {url}, 参数: {params}")
            start_time = time.time()
            response = requests.get(url, params=params, headers=self.headers)
            elapsed_time = time.time() - start_time
            
            self.logger.info(f"API响应时间: {elapsed_time:.2f}秒, 状态码: {response.status_code}")
            
            # 记录原始响应内容
            self.logger.debug(f"API原始响应: {response.text[:500]}..." if len(response.text) > 500 else response.text)
            
            data = response.json()
            
            if data["code"] == 1 and "data" in data:
                # 记录数据条数
                symbols_count = len(data["data"])
                self.logger.info(f"成功获取{symbols_count}只股票的报价数据")
                
                # 解析返回的数据
                quotes_data = []
                for symbol, quote in data["data"].items():
                    quote["symbol"] = symbol
                    quotes_data.append(quote)
                
                # 转换为DataFrame
                df = pd.DataFrame(quotes_data)
                return df
            else:
                error_msg = f"获取股票报价失败: {data.get('msg', '未知错误')}"
                self.logger.error(error_msg)
                print(error_msg)
                return pd.DataFrame()
        except Exception as e:
            error_msg = f"获取股票报价时出错: {str(e)}"
            self.logger.error(error_msg)
            print(error_msg)
            return pd.DataFrame()
    
    def get_stock_rank(self, sort_field="changeRate", ascending=False, page=1, limit=100, market="hs_a"):
        """获取股票排行
        
        Args:
            sort_field: 排序字段，可选：changeRate(涨跌率), volume(成交量), value(成交额), 
                        amplitude(振幅), turnOver(换手率), volumeRatio(量比), pe(市盈率), 
                        pb(市净率), totalShare(总市值)
            ascending: 是否升序，True为升序，False为降序
            page: 页码
            limit: 每页条数，最大100条
            market: 市场代码，可选：hs_a(沪深A股), hs_b(沪深B股), hs_bjs(北交所), 
                   kcb(科创板), cyb(创业板), hs(沪深所有)
        
        Returns:
            包含股票排行信息的DataFrame
        """
        # 构建请求URL
        url = f"{self.base_url}/hs/rank"
        params = {
            "sort": sort_field,
            "asc": 1 if ascending else 0,
            "page": page,
            "limit": limit,
            "market": market
        }
        
        try:
            self.logger.info(f"请求股票排行API: {url}, 参数: {params}")
            start_time = time.time()
            response = requests.get(url, params=params, headers=self.headers)
            elapsed_time = time.time() - start_time
            
            self.logger.info(f"API响应时间: {elapsed_time:.2f}秒, 状态码: {response.status_code}")
            
            # 记录原始响应内容
            self.logger.debug(f"API原始响应: {response.text[:500]}..." if len(response.text) > 500 else response.text)
            
            data = response.json()
            
            if data["code"] == 1 and "data" in data:
                # 记录数据条数
                stocks_count = len(data["data"])
                self.logger.info(f"成功获取{stocks_count}只股票的排行数据")
                
                # 转换为DataFrame
                df = pd.DataFrame(data["data"])
                
                # 记录前5只股票的代码和名称
                if not df.empty and len(df) >= 5:
                    top5 = df.head(5)
                    self.logger.info(f"排行前5只股票: {top5[['symbol', 'name']].values.tolist()}")
                
                return df
            else:
                error_msg = f"获取股票排行失败: {data.get('message', '未知错误')}"
                self.logger.error(error_msg)
                print(error_msg)
                return pd.DataFrame()
        except Exception as e:
            error_msg = f"获取股票排行时出错: {str(e)}"
            self.logger.error(error_msg)
            print(error_msg)
            return pd.DataFrame()
    
    def get_stock_info(self, code):
        """获取股票详细信息
        
        Args:
            code: 股票代码，如 "000001.SZ"
        
        Returns:
            包含股票详细信息的字典
        """
        # 构建请求URL
        url = f"{self.base_url}/hs_info"
        params = {
            "code": code
        }
        
        try:
            self.logger.info(f"请求股票详细信息API: {url}, 参数: {params}")
            start_time = time.time()
            response = requests.get(url, params=params, headers=self.headers)
            elapsed_time = time.time() - start_time
            
            self.logger.info(f"API响应时间: {elapsed_time:.2f}秒, 状态码: {response.status_code}")
            
            # 记录原始响应内容
            self.logger.debug(f"API原始响应: {response.text[:500]}..." if len(response.text) > 500 else response.text)
            
            data = response.json()
            
            if data["code"] == 20000 and "data" in data:
                # 记录关键财务指标
                stock_data = data["data"]
                self.logger.info(f"成功获取股票 {code} 的详细信息")
                self.logger.info(f"股票名称: {stock_data.get('prod_name', 'N/A')}, "  
                               f"最新价: {stock_data.get('last_px', 'N/A')}, " 
                               f"PE: {stock_data.get('pe', 'N/A')}, " 
                               f"PB: {stock_data.get('pb_rate', 'N/A')}, " 
                               f"市值(亿): {float(stock_data.get('market_value', 0)) / 100000000:.2f}")
                return stock_data
            else:
                error_msg = f"获取股票 {code} 信息失败: {data.get('message', '未知错误')}"
                self.logger.error(error_msg)
                print(error_msg)
                return {}
        except Exception as e:
            error_msg = f"获取股票 {code} 信息时出错: {str(e)}"
            self.logger.error(error_msg)
            print(error_msg)
            return {}
    
    def get_stock_fund_flow(self, symbol):
        """获取股票资金流向
        
        Args:
            symbol: 股票纯数字代码，如 "000002"
        
        Returns:
            包含资金流向信息的字典
        """
        # 构建请求URL
        url = f"{self.base_url}/f10/fundflow"
        params = {
            "symbol": symbol
        }
        
        try:
            self.logger.info(f"请求股票资金流向API: {url}, 参数: {params}")
            start_time = time.time()
            response = requests.get(url, params=params, headers=self.headers)
            elapsed_time = time.time() - start_time
            
            self.logger.info(f"API响应时间: {elapsed_time:.2f}秒, 状态码: {response.status_code}")
            
            # 记录原始响应内容
            self.logger.debug(f"API原始响应: {response.text[:500]}..." if len(response.text) > 500 else response.text)
            
            data = response.json()
            
            if data["code"] == 1 and "data" in data:
                flow_data = data["data"]
                self.logger.info(f"成功获取股票 {symbol} 的资金流向数据")
                self.logger.info(f"总流入: {flow_data.get('total_inflow', 'N/A')}, " 
                               f"主力净流入: {flow_data.get('main_net_inflow', 'N/A')}, " 
                               f"超大单净流入: {flow_data.get('super_large_net_inflow', 'N/A')}")
                return flow_data
            else:
                error_msg = f"获取股票 {symbol} 资金流向失败: {data.get('msg', '未知错误')}"
                self.logger.error(error_msg)
                print(error_msg)
                return {}
        except Exception as e:
            error_msg = f"获取股票 {symbol} 资金流向时出错: {str(e)}"
            self.logger.error(error_msg)
            print(error_msg)
            return {}
    
    def get_kline_data(self, symbol, kline_type=240, limit=90, ma=5):
        """获取K线数据
        
        Args:
            symbol: 股票代码，如 "sh000001"
            kline_type: K线类型，1:1分钟，5：五分钟；15：15分钟；30:30分钟，60:60分钟，
                      120:120分钟，240:日K，1200:周K，7200:月K，86400:年K
            limit: 返回条数，默认90条
            ma: 返回ma均线，可选值为：5,10,15,20,25,30，可不传
        
        Returns:
            包含K线数据的DataFrame
        """
        # 构建请求URL
        url = f"{self.base_url}/hs/kline"
        
        params = {
            "symbol": symbol,
            "type": kline_type,
            "limit": limit
        }
        
        if ma:
            params["ma"] = ma
        
        try:
            self.logger.info(f"请求K线API: {url}, 参数: {params}")
            start_time = time.time()
            response = requests.get(url, params=params, headers=self.headers)
            elapsed_time = time.time() - start_time
            
            self.logger.info(f"API响应时间: {elapsed_time:.2f}秒, 状态码: {response.status_code}")
            
            # 记录原始响应内容
            self.logger.debug(f"API原始响应: {response.text[:500]}..." if len(response.text) > 500 else response.text)
            
            data = response.json()
            
            if data.get("code") == 1 and "data" in data:
                # 获取K线数据
                kline_data = data["data"]
                
                if not kline_data:
                    self.logger.warning(f"未获取到K线数据")
                    return pd.DataFrame()
                
                # 转换为DataFrame
                df = pd.DataFrame(kline_data)
                
                # 重命名列
                if not df.empty:
                    # 基本列
                    columns = {
                        'day': '日期',
                        'open': '开盘价',
                        'close': '收盘价',
                        'high': '最高价',
                        'low': '最低价',
                        'volume': '成交量'
                    }
                    
                    # 均线列
                    ma_columns = {}
                    for m in [5, 10, 15, 20, 25, 30]:
                        if f'ma_price{m}' in df.columns:
                            ma_columns[f'ma_price{m}'] = f'MA{m}'
                        if f'ma_volume{m}' in df.columns:
                            ma_columns[f'ma_volume{m}'] = f'成交量MA{m}'
                    
                    # 合并所有列名映射
                    columns.update(ma_columns)
                    
                    # 只选择存在的列
                    existing_columns = {col: new_name for col, new_name in columns.items() if col in df.columns}
                    df = df.rename(columns=existing_columns)
                    
                    # 转换数据类型
                    numeric_columns = ['开盘价', '收盘价', '最高价', '最低价', '成交量']
                    for col in numeric_columns:
                        if col in df.columns:
                            df[col] = pd.to_numeric(df[col], errors='coerce')
                    
                    # 转换MA列
                    for col in df.columns:
                        if col.startswith('MA') or col.startswith('成交量MA'):
                            df[col] = pd.to_numeric(df[col], errors='coerce')
                    
                    # 转换日期
                    if '日期' in df.columns:
                        # 检查日期格式
                        if isinstance(df['日期'].iloc[0], (int, float)):
                            # 如果是时间戳，转换为日期时间
                            df['日期'] = pd.to_datetime(df['日期'], unit='s')
                        else:
                            # 如果是字符串，尝试不同的格式
                            try:
                                df['日期'] = pd.to_datetime(df['日期'])
                            except:
                                # 如果失败，保持原样
                                pass
                    
                    # 按日期排序
                    if '日期' in df.columns:
                        df = df.sort_values('日期')
                
                self.logger.info(f"成功获取K线数据，共{len(df)}条记录")
                return df
            else:
                error_msg = f"获取K线数据失败: {data.get('message', '未知错误')}"
                self.logger.error(error_msg)
                print(error_msg)
                return pd.DataFrame()
        
        except Exception as e:
            error_msg = f"获取K线数据出错: {str(e)}"
            self.logger.error(error_msg)
            print(error_msg)
            return pd.DataFrame()
    
    def get_stock_history(self, symbol, days=90):
        """获取股票历史交易数据
        
        Args:
            symbol: 股票代码，如 "sh000001"
            days: 获取的天数，默认90天
        
        Returns:
            包含历史交易数据的DataFrame
        """
        # 使用K线接口获取日K数据
        df = self.get_kline_data(symbol, kline_type=240, limit=days, ma=5)
        
        if not df.empty:
            # 添加额外列
            if '收盘价' in df.columns and '开盘价' in df.columns:
                df['涨跌额'] = df['收盘价'] - df['开盘价']
                
                # 计算涨跌幅
                df['涨跌幅'] = 0.0
                mask = df['开盘价'] > 0
                df.loc[mask, '涨跌幅'] = (df.loc[mask, '收盘价'] - df.loc[mask, '开盘价']) / df.loc[mask, '开盘价'] * 100
            
            # 计算振幅
            if '最高价' in df.columns and '最低价' in df.columns and '开盘价' in df.columns:
                df['振幅'] = 0.0
                mask = df['开盘价'] > 0
                df.loc[mask, '振幅'] = (df.loc[mask, '最高价'] - df.loc[mask, '最低价']) / df.loc[mask, '开盘价'] * 100
        
        return df
    
    def get_stock_detail(self, symbol):
        """获取股票详细信息，包括基本面和最近交易数据
        
        Args:
            symbol: 股票代码，如 "sh000001"
        
        Returns:
            (basic_info, trading_data, error): 基本面信息字典、交易数据DataFrame和错误信息
        """
        try:
            self.logger.info(f"开始获取股票详细信息: {symbol}")
            
            # 获取股票报价
            quotes = self.get_stock_quotes([symbol])
            if quotes.empty:
                return {}, pd.DataFrame(), "获取股票报价失败"
            
            # 获取股票基本信息
            stock_code = symbol.replace("sh", "").replace("sz", "")
            if symbol.startswith("sh"):
                full_code = f"{stock_code}.SH"
            elif symbol.startswith("sz"):
                full_code = f"{stock_code}.SZ"
            elif symbol.startswith("bj"):
                full_code = f"{stock_code}.BJ"
            else:
                return {}, pd.DataFrame(), f"无法识别的股票代码格式: {symbol}"
            
            info = self.get_stock_info(full_code)
            if not info:
                return {}, pd.DataFrame(), "获取股票基本信息失败"
            
            # 获取资金流向
            fund_flow = self.get_stock_fund_flow(stock_code)
            
            # 获取历史交易数据
            trading_data = self.get_stock_history(symbol, days=90)
            if trading_data.empty:
                return {}, pd.DataFrame(), "获取股票历史交易数据失败"
            
            # 整合基本面信息
            basic_info = {
                "股票代码": symbol,
                "股票名称": quotes.iloc[0]["name"] if not quotes.empty else "",
                "最新价": float(quotes.iloc[0]["price"]) if not quotes.empty else 0,
                "涨跌幅": float(quotes.iloc[0]["changeRate"]) if not quotes.empty else 0,
                "市盈率(TTM)": float(info.get("pe", 0)),
                "市净率": float(info.get("pb_rate", 0)),
                "总市值(亿)": float(info.get("market_value", 0)) / 100000000,
                "流通市值(亿)": float(info.get("circ_mv", 0)) / 100000000 if "circ_mv" in info else float(info.get("market_value", 0)) / 100000000 * 0.7,
                "总股本(亿)": float(info.get("total_share", 0)) / 100000000 if "total_share" in info else 0,
                "流通股本(亿)": float(info.get("float_share", 0)) / 100000000 if "float_share" in info else 0,
                "股息率(%)": float(info.get("dv_ratio", 0)) if "dv_ratio" in info else 0,
                "行业": info.get("industry", ""),
                "52周最高": float(info.get("high52w", 0)) if "high52w" in info else float(info.get("high", 0)),
                "52周最低": float(info.get("low52w", 0)) if "low52w" in info else float(info.get("low", 0)),
                "主力资金净流入(万)": fund_flow.get("main_net_inflow", 0) if fund_flow else 0,
                "超大单净流入(万)": fund_flow.get("super_large_net_inflow", 0) if fund_flow else 0,
                "大单净流入(万)": fund_flow.get("big_net_inflow", 0) if fund_flow else 0,
                "中单净流入(万)": fund_flow.get("mid_net_inflow", 0) if fund_flow else 0,
                "小单净流入(万)": fund_flow.get("small_net_inflow", 0) if fund_flow else 0
            }
            
            self.logger.info(f"成功获取股票详细信息: {symbol}")
            return basic_info, trading_data, None
            
        except Exception as e:
            error_msg = f"获取股票详细信息出错: {str(e)}"
            self.logger.error(error_msg)
            return {}, pd.DataFrame(), error_msg
    
    def get_value_stocks(self, pe_threshold=15, pb_threshold=1.5, div_yield_threshold=4, 
                         market_cap_threshold=100, drop_min=2, drop_max=6, limit=100):
        """获取价值股
        
        Args:
            pe_threshold: 市盈率阈值，低于该值的股票被视为价值股
            pb_threshold: 市净率阈值，低于该值的股票被视为价值股
            div_yield_threshold: 股息率阈值，高于该值的股票被视为价值股
            market_cap_threshold: 市值阈值（亿元），高于该值的股票被视为价值股
            drop_min: 最小跌幅百分比
            drop_max: 最大跌幅百分比
            limit: 获取的股票数量
        
        Returns:
            包含价值股信息的DataFrame
        """
        self.logger.info(f"开始获取价值股，参数: PE<{pe_threshold}, PB<{pb_threshold}, 股息率>{div_yield_threshold}, " 
                       f"市值>{market_cap_threshold}亿, 跌幅范围: {drop_min}%-{drop_max}%, 获取数量: {limit}")
        try:
            # 1. 获取股票排行（按成交额排序）
            self.logger.info("步骤1: 获取股票排行（按成交额排序）")
            stocks = self.get_stock_rank(sort_field="value", ascending=False, limit=limit)
            if stocks.empty:
                error_msg = "无法获取股票排行数据"
                self.logger.error(error_msg)
                return pd.DataFrame(), error_msg
            
            self.logger.info(f"成功获取{len(stocks)}只股票的排行数据")
            print(f"成功获取{len(stocks)}只股票的排行数据")
            
            # 2. 筛选价值股
            self.logger.info("步骤2: 筛选价值股")
            value_stocks = []
            
            # 批量处理，每批10个股票
            batch_size = 10
            total_batches = (len(stocks) + batch_size - 1) // batch_size
            
            self.logger.info(f"将分{total_batches}批处理，每批{batch_size}只股票")
            
            for batch_idx in range(total_batches):
                start_idx = batch_idx * batch_size
                end_idx = min((batch_idx + 1) * batch_size, len(stocks))
                batch_stocks = stocks.iloc[start_idx:end_idx]
                
                batch_log = f"处理第{batch_idx+1}/{total_batches}批股票，共{len(batch_stocks)}只..."
                self.logger.info(batch_log)
                print(batch_log)
                
                for _, stock in batch_stocks.iterrows():
                    symbol = stock["symbol"]
                    # 提取纯数字代码
                    code = symbol[2:]
                    
                    # 获取股票详细信息
                    if symbol.startswith("sh"):
                        full_code = f"{code}.SH"
                    elif symbol.startswith("sz"):
                        full_code = f"{code}.SZ"
                    elif symbol.startswith("bj"):
                        full_code = f"{code}.BJ"
                    else:
                        self.logger.warning(f"无法识别的股票代码格式: {symbol}")
                        continue
                    
                    self.logger.info(f"获取股票 {symbol}({stock['name']}) 的详细信息，完整代码: {full_code}")
                    stock_info = self.get_stock_info(full_code)
                    if not stock_info:
                        self.logger.warning(f"未能获取到股票 {symbol}({stock['name']}) 的详细信息")
                        continue
                    
                    # 提取关键财务指标
                    try:
                        pe = float(stock_info.get("pe", float("inf")))
                        pb = float(stock_info.get("pb_rate", float("inf")))
                        # 股息率需要从其他接口获取，这里暂时设为0
                        div_yield = 0
                        market_cap = float(stock_info.get("market_value", 0)) / 100000000  # 转换为亿元
                        
                        # 计算跌幅
                        price = float(stock_info.get("last_px", 0))
                        preclose = float(stock_info.get("preclose_px", 0))
                        if preclose > 0:
                            change_rate = (price - preclose) / preclose * 100
                        else:
                            change_rate = 0
                        
                        # 应用格雷厄姆标准
                        if (pe < pe_threshold and pb < pb_threshold and 
                            market_cap >= market_cap_threshold and 
                            change_rate <= -drop_min and change_rate >= -drop_max):
                            
                            # 添加到价值股列表
                            value_stock = {
                                "代码": symbol,
                                "名称": stock["name"],
                                "最新价": price,
                                "涨跌幅": change_rate,
                                "市盈率": pe,
                                "市净率": pb,
                                "股息率": div_yield,
                                "总市值(亿)": market_cap,
                                "成交量": float(stock.get("volume", 0)),
                                "成交额": float(stock.get("value", 0))
                            }
                            value_stocks.append(value_stock)
                            success_msg = f"找到价值股: {symbol}, {stock['name']}, PE: {pe:.2f}, PB: {pb:.2f}, 跌幅: {change_rate:.2f}%"
                            self.logger.info(success_msg)
                            print(success_msg)
                        else:
                            self.logger.debug(f"股票 {symbol}({stock['name']}) 不符合价值股标准: PE={pe:.2f}, PB={pb:.2f}, " 
                                             f"市值={market_cap:.2f}亿, 跌幅={change_rate:.2f}%")
                    except Exception as e:
                        print(f"处理股票{symbol}时出错: {str(e)}")
                        continue
            
            # 转换为DataFrame
            result = pd.DataFrame(value_stocks)
            if result.empty:
                error_msg = "未找到符合条件的价值股"
                self.logger.warning(error_msg)
                return pd.DataFrame(), error_msg
            
            # 按跌幅排序（升序，跌幅越大排名越前）
            result = result.sort_values(by="涨跌幅", ascending=True)
            
            success_msg = f"成功筛选出{len(result)}只价值股"
            self.logger.info(success_msg)
            self.logger.info(f"前5只价值股: {result[['代码', '名称', '涨跌幅']].head(5).values.tolist()}")
            print(success_msg)
            return result, None
        except Exception as e:
            error_msg = f"获取价值股时出错: {str(e)}"
            print(error_msg)
            return pd.DataFrame(), error_msg
